SpringBoot集成Quartz实现分布式任务调度 | 您所在的位置:网站首页 › quartz 集群可配置 › SpringBoot集成Quartz实现分布式任务调度 |
前言
本篇内容包括 SpringBoot整合Quartz Quartz持久化 分布式任务调度 一、介绍 1.1 Quartz集群 Quartz集群中每个节点都是一个单独的Quartz应用,它又管理着其他的节点。这个集群需要每个节点单独的启动或停止;和我们的应用服务器集群不同,独立的Quratz节点之间是不需要通信的。不同节点之间是通过数据库表来感知另一个应用。只有使用持久的JobStore才能完成Quartz集群。 Quartz持久化配置提供了两种存储器: 类型优点缺点RAMJobStore不要外部数据库,配置容易,运行速度快因为调度程序信息是存储在被分配给 JVM 的内存里面,所以,当应用程序停止运行时,所有调度信息将被丢失。另外因为存储到JVM内存里面,所以可以存储多少个 Job 和 Trigger 将会受到限制JDBC 作业存储支持集群,因为所有的任务信息都会保存到数据库中,可以控制事物,还有就是如果应用服务器关闭或者重启,任务信息都不会丢失,并且可以恢复因服务器关闭或者重启而导致执行失败的任务运行速度的快慢取决与连接数据库的快慢 二、操作步骤需要提前创建一个SpringBoot项目 2.1 引入依赖包 org.springframework.boot spring-boot-starter-web commons-lang commons-lang 2.5 mysql mysql-connector-java 5.1.39 com.mchange c3p0 0.9.5.4 2.2 配置文件通过在application.yml配置文件中对quartz进行相关配置。 server: port: 8090 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/quartz?characterEncoding=utf-8&useSSL=false username: root password: 123456 quartz: jdbc: initialize-schema: never # 是否自动使用 SQL 初始化 Quartz 表结构。always:总是,never:不需要 job-store-type: jdbc # Job 存储器类型。默认为 memory 表示内存,可选 jdbc 使用数据库。 properties: org: quartz: scheduler: instanceName: QuartzScheduler # 调度标识名 集群中每一个实例都必须使用相同的名称 instanceId: AUTO # 定时任务的实例编号, 如果手动指定需要保证每个节点的唯一性 threadPool: class: org.quartz.simpl.SimpleThreadPool threadCount: 100 # 线程池大小。默认为 10 。 threadPriority: 5 # 线程优先级 jobStore: misfireThreshold: 120000说明:application.yml文件中的配置相当与Quartz中quartz.properties配置文件 2.3 创建数据库表 Quartz持久化过程创建数据库表方式第一种 将yml文件中配置项initialize-schema在第一次执行时指定为always,会自动在数据库中生成表信息,当表创建完成后在将参数改成never initialize-schema: always第二种 在官网中下载Quartz对应版本的安装包在docs\dbTables目录下找到tables_mysql_innodb.sql文件在数据库中执行SQL。 官网下载地址:www.quartz-scheduler.org/downloads/ 数据库表结构说明 表名说明qrtz_blob_triggers以Blob 类型存储的触发器qrtz_calendars存放日历信息, quartz可配置一个日历来指定一个时间范围qrtz_cron_triggers存放cron类型的触发器qrtz_fired_triggers存放已触发的触发器qrtz_job_details存放一个jobDetail信息qrtz_job_listenersjob监听器qrtz_locks存储程序的悲观锁的信息(假如使用了悲观锁)qrtz_paused_trigger_graps存放暂停掉的触发器qrtz_scheduler_state调度器状态qrtz_simple_triggers简单触发器的信息qrtz_trigger_listeners触发器监听器qrtz_triggers触发器的基本信息 2.4 定义Job QuartzJobFirst import com.dataojo.quartz.util.SchedulerUtils; import org.quartz.*; import org.springframework.scheduling.quartz.QuartzJobBean; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; /** * @author lilinchao * @date 2021/9/2 * @description 1.0 **/ @PersistJobDataAfterExecution @DisallowConcurrentExecution public class QuartzJobFirst extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext){ SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); List executionContexts; try { executionContexts = SchedulerUtils.getScheduler().getCurrentlyExecutingJobs(); } catch (SchedulerException e) { e.printStackTrace(); return; } for (JobExecutionContext executionContext : executionContexts){ JobKey jobKey = executionContext.getJobDetail().getKey(); Date fireTime = executionContext.getFireTime(); System.out.println(jobKey+",对应的执行时间是"+sf.format(fireTime)); } } } QuartzJobTwo import org.quartz.*; import org.springframework.scheduling.quartz.QuartzJobBean; import java.text.SimpleDateFormat; import java.util.Date; /** * @author lilinchao * @date 2021/9/2 * @description 1.0 **/ @PersistJobDataAfterExecution @DisallowConcurrentExecution public class QuartzJobTwo extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext){ SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("QuartzJobTwo执行时间是"+sf.format(new Date())); } }说明 QuartzJobBean QuartzJobBean已经实现了job接口,并重写了接口中的execute()方法,在SpringBoot集成时候直接继承QuartzJobBean即可。执行逻辑在executeInternal()方法中。 @PersistJobDataAfterExecution 告诉Quartz在成功执行了Job实现类的execute方法后(没有发生任何异常),更新JobDetail中JobDataMap的数据,使得该JobDetail实例在下一次执行的时候,JobDataMap中是更新后的数据,而不是更新前的旧数据。 @DisallowConcurrentExecution 告诉Quartz不要并发地执行同一个JobDetail实例。 总结 当某一个JobDetail实例到点运行之后,在其运行结束之前,不会再发起一次该JobDetail实例的调用,即使设置的该JobDetail实例的定时执行时间到了。 JobDetail实例之间互不影响。 2.5 实现ApplicationListener 完成动态调度 根据ApplicationListener的原理,其onApplicationEvent(ContextRefreshedEvent event) 方法会在初始化所有的bean之后被调用,因此我们可以在这里进行scheduler的创建、启动,以及注册trigger和job。 import com.dataojo.quartz.job.QuartzJobFirst; import com.dataojo.quartz.job.QuartzJobTwo; import com.dataojo.quartz.util.SchedulerUtils; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; /** * @author lilinchao * @date 2021/9/2 * @description 1.0 **/ @Component public class StartApplicationListener implements ApplicationListener { @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { System.out.println("-------执行StartApplicationListener--------"); SchedulerUtils.scheduleCronJob(QuartzJobFirst.class, "*/5 * * * * ?"); SchedulerUtils.scheduleCronJob(QuartzJobTwo.class, "*/10 * * * * ?"); } } 2.6 工具类 SchedulerUtils import org.apache.commons.lang.time.DateUtils; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.ParseException; import java.util.Date; /** * @author lilinchao * @date 2021/9/3 * @description 1.0 */ public class SchedulerUtils { private static final Logger LOGGER = LoggerFactory.getLogger(SchedulerUtils.class); private static Scheduler scheduler; private static String jobGroup = "group"; static { if (SpringContextUtils.getApplicationContext() != null) { scheduler = SpringContextUtils.getBean(Scheduler.class); } else { SchedulerFactory schedulerFactory = new StdSchedulerFactory(); try { scheduler = schedulerFactory.getScheduler(); scheduler.start(); } catch (SchedulerException e) { throw new RuntimeException(e); } } } private SchedulerUtils() { } public static Scheduler getScheduler() { return scheduler; } public static void scheduleCronJob(Class |
CopyRight 2018-2019 实验室设备网 版权所有 |